/*
1. Ban list for a given instance, should be optional
2. The big fat collection as parameter, client responsibility to parse that collection and decide what to do when a new response is add it
3. Method that notify when one new source has been resolved... future
 */
package org.biodas.jdas.client.threads;

import org.apache.log4j.Logger;
import org.biodas.jdas.client.FeaturesClient;
import org.biodas.jdas.client.adapters.features.DasGFFAdapter;
import org.biodas.jdas.exceptions.DASClientException;

import java.util.*;

/**
 * Created by IntelliJ IDEA.
 * User: ljgarcia
 * Date: 30/11/11
 * Time: 14:50
 * To change this template use File | Settings | File Templates.
 */
public class FeaturesClientMultipleSources extends ClientMultipleSources  {
    private static Logger logger = Logger.getLogger(FeaturesClientMultipleSources.class);

    /**
     * Fetches data from multiple sources for a list of segments; segments can include ranges.
     * The invoking method is responsible for processing the results.
     * @param sources List of sources (url)
     * @param segments List of segments
     * @param results Map of (source name, (list of segments, DASGFF responses)) one for each source successfully queried
     * @param errors  Map of (source name, (list of segments, exceptions)) one for each source raising an exception
     */
    public void fetchData(List<String> sources, final List<String> segments, final Map<String, Map<List<String>, DasGFFAdapter>> results, final Map<String, Map<List<String>, Exception>> errors) {
        for (final String source: sources) {
            this.runTask(new Runnable() {
                @Override
                public void run() {
                    try {
                        FeaturesClient featuresClient = new FeaturesClient();
                        DasGFFAdapter adapter = featuresClient.fetchData(source, segments);
                        if (results.get(source) == null) {
                            Map<List<String>, DasGFFAdapter> response = new HashMap<List<String>, DasGFFAdapter>();
                            response.put(segments, adapter);
                            results.put(source, response);
                        } else {
                            results.get(source).put(segments, adapter);
                        }
                        logger.debug("Response from " + source + " has been already retrieved");
                    } catch (DASClientException e) {
                        if (errors.get(source) == null) {
                            Map<List<String>, Exception> response = new HashMap<List<String>, Exception>();
                            response.put(segments, e);
                            errors.put(source, response);
                        } else {
                            errors.get(source).put(segments, e);
                        }
                        logger.error("Fetching data from source " + source + " raised an exception: " + e.getMessage());
                        //e.printStackTrace();
                    }
                }
            });
        }
        while (!queue.isEmpty() ) {
            logger.info("Waiting for " + queue.size() + " jobs");
        }
    }

    /**
     * Fetch data from multiple sources for a list of segments; segments can include ranges.
     * The invoking method is responsible for processing the results.
     * Please note that results are identified by source and segments, it is not advisable to use the same instance to
     * query the same sources with the same segments but different methods as the results will be replaced.
     * @param sources List of sources (url)
     * @param segments List of segments
     * @param types List of types
     * @param results Map of (source name, (list of segments, DASGFF responses)) one for each source successfully queried
     * @param errors  Map of (source name, (list of segments, exceptions)) one for each source raising an exception
     */
    public void fetchDataWithTypes(List<String> sources, final List<String> segments, final List<String>types, final Map<String, Map<List<String>, DasGFFAdapter>> results, final Map<String, Map<List<String>, Exception>> errors) {
        for (final String source: sources) {
            this.runTask(new Runnable() {
                @Override
                public void run() {
                    try {
                        FeaturesClient featuresClient = new FeaturesClient();
                        DasGFFAdapter adapter = featuresClient.fetchDataWithTypes(source, segments, types);
                        if (results.get(source) == null) {
                            Map<List<String>, DasGFFAdapter> response = new HashMap<List<String>, DasGFFAdapter>();
                            response.put(segments, adapter);
                            results.put(source, response);
                        } else {
                            results.get(source).put(segments, adapter);
                        }
                        logger.debug("Response from " + source + " has been already retrieved");
                    } catch (DASClientException e) {
                        if (errors.get(source) == null) {
                            Map<List<String>, Exception> response = new HashMap<List<String>, Exception>();
                            response.put(segments, e);
                            errors.put(source, response);
                        } else {
                            errors.get(source).put(segments, e);
                        }
                        logger.error("Fetching data from source " + source + " raised an exception: " + e.getMessage());
                    }
                }
            });
        }
        while (!queue.isEmpty() ) {
            logger.info("Waiting for " + queue.size() + " jobs");
        }
    }

    /**
     * Fetch data from multiple sources for a list of segments; segments can include ranges.
     * The invoking method is responsible for processing the results.
     * Please note that results are identified by source and segments, it is not advisable to use the same instance to
     * query the same sources with the same segments but different methods as the results will be replaced.
     * @param sources List of sources (url)
     * @param segments List of segments
     * @param featureIds List of feature ids
     * @param results Map of (source name, (list of segments, DASGFF responses)) one for each source successfully queried
     * @param errors  Map of (source name, (list of segments, exceptions)) one for each source raising an exception
     */
    public void fetchDataWithFeatueIds(List<String> sources, final List<String> segments, final List<String> featureIds, final Map<String, Map<List<String>, DasGFFAdapter>> results, final Map<String, Map<List<String>, Exception>> errors) {
        for (final String source: sources) {
            this.runTask(new Runnable() {
                @Override
                public void run() {
                    try {
                        FeaturesClient featuresClient = new FeaturesClient();
                        DasGFFAdapter adapter = featuresClient.fetchDataWithFeatueIds(source, segments, featureIds);
                        if (results.get(source) == null) {
                            Map<List<String>, DasGFFAdapter> response = new HashMap<List<String>, DasGFFAdapter>();
                            response.put(segments, adapter);
                            results.put(source, response);
                        } else {
                            results.get(source).put(segments, adapter);
                        }
                        logger.debug("Response from " + source + " has been already retrieved");
                    } catch (DASClientException e) {
                        if (errors.get(source) == null) {
                            Map<List<String>, Exception> response = new HashMap<List<String>, Exception>();
                            response.put(segments, e);
                            errors.put(source, response);
                        } else {
                            errors.get(source).put(segments, e);
                        }
                        logger.error("Fetching data from source " + source + " raised an exception: " + e.getMessage());
                    }
                }
            });
        }
        while (!queue.isEmpty() ) {
            logger.info("Waiting for " + queue.size() + " jobs");
        }
    }

    /**
     /**
     * Fetch data from multiple sources for a list of segments; segments can include ranges.
     * The invoking method is responsible for processing the results.
     * Please note that results are identified by source and segments, it is not advisable to use the same instance to
     * query the same sources with the same segments but different methods as the results will be replaced.
     * @param sources List of sources (url)
     * @param segments List of segments
     * @param types List of types
     * @param categories List of categories
     * @param categorize
     * @param featureIds List of feature ids
     * @param maxbins
     * @param results Map of (source name, (list of segments, DASGFF responses)) one for each source successfully queried
     * @param errors  Map of (source name, (list of segments, exceptions)) one for each source raising an exception
     */
    public void fetchData(List<String> sources, final List<String> segments, final List<String> types
        , final List<String> categories, final String categorize, final List<String> featureIds, final String maxbins
        , final Map<String, Map<List<String>, DasGFFAdapter>> results, final Map<String, Map<List<String>, Exception>> errors) {
        for (final String source: sources) {
            this.runTask(new Runnable() {
                @Override
                public void run() {
                    try {
                        FeaturesClient featuresClient = new FeaturesClient();
                        DasGFFAdapter adapter = featuresClient.fetchData(source, segments, types, categories, categorize, featureIds, maxbins);
                        if (results.get(source) == null) {
                            Map<List<String>, DasGFFAdapter> response = new HashMap<List<String>, DasGFFAdapter>();
                            response.put(segments, adapter);
                            results.put(source, response);
                        } else {
                            results.get(source).put(segments, adapter);
                        }
                        logger.debug("Response from " + source + " has been already retrieved");
                    } catch (DASClientException e) {
                        if (errors.get(source) == null) {
                            Map<List<String>, Exception> response = new HashMap<List<String>, Exception>();
                            response.put(segments, e);
                            errors.put(source, response);
                        } else {
                            errors.get(source).put(segments, e);
                        }
                        logger.error("Fetching data from source " + source + " raised an exception: " + e.getMessage());
                    }
                }
            });
        }
        while (!queue.isEmpty() ) {
            logger.info("Waiting for " + queue.size() + " jobs");
        }
    }
}
